/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <memory.h>
#include <getopt.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#include <ncurses.h>
#include <sys/ioctl.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>

#include "device.h"
#include "utils.h"
#include "win.h"
#include "tuner_atsc.h"
#include "mpegts_io.h"

#define ATSC_VERSION_STR					"tuner_atsc v1\n"
#define ATSC_MAX_DEV_COUNT					64
//#define ATSC_DEFAULT_READ_SZ				(TS_PACKET_SIZE * 5200)
#define ATSC_DEFAULT_READ_SZ				(TS_PACKET_SIZE * 171)
#define ATSC_DEFAULT_BINDIP					"0.0.0.0"
#define ATSC_DEFAULT_BINDPORT				8988

#define ATSC_DEFAULT_CHANNELS_CONF			"channels.conf"
#define CHANNELS_CONF_ID_ATSC				"B8M10"
#define CHANNELS_CONF_ID_QAM256				"B8M256"
#define ATSC_DVB_DEFAULT_PATH				"/dev/dvb/adapter"

// Callback(s) for device

uint8_t atsc_read_data(TUNER_STRUCT *);
//int atsc_tune_channel(TUNER_STRUCT *, uint32_t);
int atsc_tune_channel(TUNER_STRUCT *, TUNER_INITPASS_STRUCT *);

// Internal functions, shouldn't be called from outside

//static int _atsc_setup_frontend (int, struct dvb_frontend_parameters *);
int _atsc_get_channel_lineup(TUNER_ATSC_STRUCT *);
int _atsc_channel_change(TUNER_STRUCT *, TUNER_CHANNEL_STRUCT *);
uint8_t atsc_update_stats(TUNER_STRUCT *);

uint8_t atsc_destroy(TUNER_STRUCT *);


int _gui_incoming_parse(char *ip, uint8_t type, uint8_t cmd)
{
//	printf("I was called: %s [%d %d]\n", ip, type, cmd);
	return 0;
}


int _atsc_set_pesfilter(int dmxfd, int pid, int pes_type, int dvr)
{
	struct dmx_pes_filter_params pesfilter;

	/* ignore this pid to allow radio services */
	if (pid < 0 || pid >= 0x1fff || (pid == 0 && pes_type != DMX_PES_OTHER))
		return 0;

	if (dvr) {
		int buffersize = 64 * 1024;
		if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
		{
//			printf("[ATSC] _atsc_set_pesfilter failed at 1\n");
		}
	}

	pesfilter.pid = pid;
	pesfilter.input = DMX_IN_FRONTEND;
	pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
	pesfilter.pes_type = pes_type;
	pesfilter.flags = DMX_IMMEDIATE_START;

	if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
//		printf("[ATSC] _atsc_set_pesfilter failed at 2\n");
		return -1;
	}
	return 0;
}

int _atsc_get_pmt_pid(char *dmxdev, int sid)
{
	int patfd, count;
	int pmt_pid = 0;
	int patread = 0;
	int section_length;
	unsigned char buft[4096];
	unsigned char *buf = buft;
	struct dmx_sct_filter_params f;

	memset(&f, 0, sizeof(f));
	f.pid = 0;
	f.filter.filter[0] = 0x00;
	f.filter.mask[0] = 0xff;
	f.timeout = 0;
	f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
//	printf("HI: %s -- %d\n", dmxdev, sid);
	if ((patfd = open(dmxdev, O_RDWR)) < 0) {
		perror("openening pat demux failed");
		return -1;
	}

	if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
		perror("ioctl DMX_SET_FILTER failed");
		close(patfd);
		return -1;
	}

	if (select_wait_read(patfd, 4, 0) <= 0)
	{
//		printf("WAIT BAD\n");
		return -1;
	}

	while (!patread) {
		if (((count = get_bytes_from_file(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
		{
			count = get_bytes_from_file(patfd, buf, sizeof(buft));
		}

		if (count < 0) {
			perror("read_sections: read error");
			close(patfd);
			return -1;
		}
		section_length = ((buf[1] & 0x0f) << 8) | buf[2];
		if (count != section_length + 3)
			continue;
		buf += 8;
		section_length -= 8;

		patread = 1; /* assumes one section contains the whole pat */
		while (section_length > 0) {
			int service_id = (buf[0] << 8) | buf[1];

			if (service_id == sid) {
				pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
				section_length = 0;
			}
			buf += 4;
			section_length -= 4;
		}

	}
	close(patfd);
	return pmt_pid;
}



int _atsc_channel_change(TUNER_STRUCT *tuner, TUNER_CHANNEL_STRUCT *chan_struct)
{
//	printf("_atsc_channel_change start\n");

	if (tuner && tuner->parent && tuner->extra_data[0] && chan_struct && chan_struct->pid_count)
	{
//		DEVICE_STRUCT *dev = (DEVICE_STRUCT *)tuner->parent;
		struct dvb_frontend_parameters *frontend_param = (struct dvb_frontend_parameters *)tuner->extra_data[0];
//		struct dmx_sct_filter_params f = {0};
		int pmt_pid;
		int i, tmp2;
		uint8_t type;

//		printf("fe: %s\n", tuner->frontend);
//		printf("dem: %s\n", tuner->demux);
//		printf("dvr: %s\n", tuner->dvr);
		memset(frontend_param, 0, sizeof(struct dvb_frontend_parameters));

		frontend_param->frequency = (uint32_t)chan_struct->program_num;
//		frontend_param->u.vsb.modulation = chan_struct->modulation_type;
		frontend_param->u.vsb.modulation = 7;

		if (ioctl(tuner->devhandle, FE_SET_FRONTEND, frontend_param) < 0)
		{
//			printf("[ATSC] Couldn't set frequency\n");
			return -1;
		}
//		printf("[ATSC] Set Frequency to: %dhz\n", frontend_param->frequency);

		pmt_pid = _atsc_get_pmt_pid(tuner->demux, chan_struct->sid);
		if (pmt_pid <= 0)
		{
			printf("[ATSC] Couldn't get PMT PID\n");
			return -1;
		}
//		printf("PMT PID: %d\n", pmt_pid);
		tuner->pmt_pid = (uint16_t) pmt_pid;

		tuner->devhandles[1] = open(tuner->demux, O_RDWR);
		if (tuner->devhandles[1] < 0)
		{
//			printf("Error 1\n");
			return -1;
		}

		if (_atsc_set_pesfilter(tuner->devhandles[1], 0, DMX_PES_OTHER, 1) < 0)
		{
//			printf("[ATSC] Couldn't set PAT Filter\n");
			return -1;
		}

		tuner->devhandles[2] = open(tuner->demux, O_RDWR);
		if (tuner->devhandles[2] < 0)
		{
//			printf("Error 2\n");
			return -1;
		}


		if (_atsc_set_pesfilter(tuner->devhandles[2], pmt_pid, DMX_PES_OTHER, 1) < 0)
		{
//			printf("[ATSC] Couldn't set PMT Filter\n");
			return -1;
		}

		for(i=0; i < chan_struct->pid_count; i++)
		{

			tuner->devhandles[3+i] = open(tuner->demux, O_RDWR);
			if (tuner->devhandles[3+i] < 0)
			{
//				printf("Error %d\n", 3+i);
				return -1;
			}
//			printf("[ATSC] Setting Filter, PID: %d\n", chan_struct->pids[i]);
			switch(chan_struct->pids_type[i])
			{
				case TUNER_CHANNEL_PID_VIDEO:
//					printf("Video");
					type = DMX_PES_VIDEO;
				break;
				case TUNER_CHANNEL_PID_AUDIO:
//					printf("Audio);
					type = DMX_PES_AUDIO;
				break;

				default:
//					printf("Other");
					type = DMX_PES_OTHER;
					break;
			}
//			printf("\n");

			type = DMX_PES_OTHER;
			tmp2 = _atsc_set_pesfilter(tuner->devhandles[3+i], chan_struct->pids[i], type, 1);
			if (tmp2 < 0)
			{
//				printf("[ATSC] Couldn't set PID Filter: %d\n", chan_struct->pids[i]);
//				return -1;
			}
		}
		tuner->devhandles[0] = open(tuner->dvr, O_RDONLY);
//		printf("Opening DVR: %s\n", tuner->dvr);
		if (tuner->devhandles[0] < 0)
		{
//			printf("[ATSC] Couldn't open DVR\n");
			return -1;
		}

	}
//	printf("_atsc_channel_change end\n");
	return 0;
}


int _atsc_get_channel_lineup(TUNER_ATSC_STRUCT *dev)
{
	int filehandle = -1;
	char *tmp_mem = NULL;
	off_t sz = 0;

	if (!dev)
	{
//	 	printf("[ATSC] _atsc_get_channel_lineup: device is null\n");
		return 1;
	}

	filehandle = open(dev->channels_file, O_RDONLY);

	if (filehandle == -1)
	{
//	 	printf("[ATSC] Can't open ATSC channel config\n");
		return 1;
	}

	sz = get_file_size(dev->channels_file);
	tmp_mem = calloc(1, sz);

	if (tmp_mem)
	{
		int bytes_read = 0;
		TEXTFILE_IN_MEMORY *memf = NULL;
		char * line = NULL;

		lseek(filehandle, 0, SEEK_SET);
		bytes_read = get_bytes_from_file(filehandle, (uint8_t *)tmp_mem, sz);

		if (bytes_read != sz)
		{
//			printf("READ ERRORORORORO: %d\n", bytes_read);
			return 0;
		}

		memf = memfile_init((char*)tmp_mem, (int)bytes_read);
		if (memf)
		{
			int count1=0, count2=0;
			int p;
			int line_count = memfile_getline_count(memf);
			char *channels[15] = {0};
			uint32_t last_channel = 0;
			uint8_t mod_type = VSB_16;
//			printf("[ATSC] Parsing Channels from: %s.. ", dev->channels_file);

			for (p=0; p < line_count; p++)
			{
				line = memfile_getnext_line(memf, 1);
				if (line && line[0] == ':' && line[1] == '@')
				{
					last_channel = atoi(line+2);
					continue;
				}

				if (line)
				{
					char *_tmpline = strdup(line);
					if (_tmpline)
					{
						uint16_t tmpnum2 = 0;
						uint64_t tmpnum1 = 0;
						char tmpstr[1024] = {0}, tmpstr2[1024] = {0};
//						printf("LINE: %s\n", _tmpline);

						channels[0] = strtok(_tmpline, ":");
						channels[1] = strtok(NULL, ":");
						channels[2] = strtok(NULL, ":");
						channels[3] = strtok(NULL, ":");
						channels[4] = strtok(NULL, ":");
						channels[5] = strtok(NULL, ":");
						channels[6] = strtok(NULL, ":");
						channels[7] = strtok(NULL, ":");
						channels[8] = strtok(NULL, ":");
						channels[9] = strtok(NULL, ":");
						channels[10] = strtok(NULL, ":");
						channels[11] = strtok(NULL, ":");
						channels[12] = strtok(NULL, ":");
						channels[13] = strtok(NULL, ":");
						channels[14] = strtok(NULL, ":");

						count1=count2=0;
						if ((memcmp(channels[2], CHANNELS_CONF_ID_ATSC, strlen(CHANNELS_CONF_ID_ATSC)) == 0) ||
							(memcmp(channels[2], CHANNELS_CONF_ID_QAM256, strlen(CHANNELS_CONF_ID_QAM256)) == 0))
						{
							int k,q;
							char *tok = NULL, *last=NULL;

							strcpy(tmpstr, channels[1]);

							for (k=5; k <= 6; k++)
								for (q=0; q < strlen(channels[k]); q++)
									if (channels[k][q] == ';')
										channels[k] = &channels[k][q+1];

							tok = strtok(channels[5], "=");
							while (tok)
							{
								last = tok;
								tok = strtok(NULL, "=");
								if (tok)
								{
									count1++;
//									printf("VPID: %s\n", last);
									strcat(tmpstr, last);
									strcat(tmpstr2, last);
									strcat(tmpstr2, ",");
								}
							}

							tok = strtok(channels[6], ",");
							while (tok)
							{
								if (tok)
								{
									uint8_t do_filter = 0;
									last = strdup(tok);
									if (last)
									{
//										printf("HERE: %s\n", last);
										for(k=1; k < strlen(last); k++)
										{
											if (last[k] == '=')
											{
												if (last[k+1] == 'e' && last[k+2] == 's' && last[k+3] == 'l')
												{
//													do_filter = 1;
//													printf("FILTERING\n");
												}
												last[k] = '\0';
												break;
											}
										}
										if (do_filter == 0)
										{
//											printf("APID: %s\n", last);
											strcat(tmpstr, last);
											strcat(tmpstr2, last);
											strcat(tmpstr2, ",");
										}
										free(last);
									}
								}
								tok = strtok(NULL, ",");
							}

//							printf("ChName: %s, %s, %s -- %s %s\n", channels[0], channels[1], channels[2], channels[3], channels[12]);

//							tmpnum = strtol(tmpstr, (char **)NULL, 10);
							tmpnum1 = strtol(channels[1], (char **)NULL, 10);

//							printf("[ATSC] PgmNum: %" PRId64"\n", tmpnum1);
							device_channel_add(dev->device, last_channel, tmpnum1);
							tok = strtok(tmpstr2, ",");
//							printf("MMMM: %d %d\n", count1, count2);
							while (tok)
							{
								if (tok)
								{
									if (count2 < count1)
										device_channel_add_pid(dev->device, last_channel, tmpnum1, atoi(tok), TUNER_CHANNEL_PID_VIDEO);
									else
										device_channel_add_pid(dev->device, last_channel, tmpnum1, atoi(tok), TUNER_CHANNEL_PID_AUDIO);
									count2++;
								}
								tok = strtok(NULL, ",");
							}
//							device_channel_add_name(dev->device, last_channel, tmpnum1, channels[12]);
							device_channel_add_name(dev->device, last_channel, tmpnum1, channels[0]);

							tmpnum2 = strtol(channels[9], (char **)NULL, 10);
							device_channel_add_sid(dev->device, last_channel, tmpnum1, tmpnum2);
							if (memcmp(channels[2], CHANNELS_CONF_ID_QAM256, strlen(CHANNELS_CONF_ID_QAM256)) == 0)
								mod_type = QAM_256;
							device_channel_set_modulation(dev->device, last_channel, tmpnum1, mod_type);
						}
						free(_tmpline);
					}
				}
			}
//			printf(" Done\n");

			free(memf);
		}

		free(tmp_mem);
	}
	return 0;
}



//int atsc_tune_channel(TUNER_STRUCT *tuner, uint32_t chan)
int atsc_tune_channel(TUNER_STRUCT *tuner, TUNER_INITPASS_STRUCT *tpass)
{
//	printf("atsc_tune_channel Start: %" PRId64"\n", tpass->channel_num);

	if (tuner && tuner->parent && tpass)
	{
		uint32_t chan = tpass->channel_num;
		TUNER_CHANNEL_STRUCT * tchan = NULL;
		DEVICE_STRUCT *dev = (DEVICE_STRUCT *)tuner->parent;

		if (dev)
		{
			tchan = device_channel_get_struct(dev, chan, 0);
			if (tchan)
			{
				if (_atsc_channel_change(tuner, tchan) != 0)
					return TUNER_TUNE_ERROR_UNKNOWN;
			}
			else
				return TUNER_TUNE_ERROR_NOCHAN;
		}
	}
	else
	{
		return TUNER_TUNE_ERROR_UNKNOWN;
//		printf("atsc_tune_channel NOOOOOO\n");
	}

//	printf("atsc_tune_channel end\n");
	return 0;
}

uint8_t atsc_close_data(TUNER_STRUCT * tuner)
{
	uint8_t ret = 1;
	if (tuner)
	{
		int i;
		for (i = 0; i < TUNER_MAX_DVB_HANDLES; i++)
		{
			if (tuner->devhandles[i] > 0)
			{
//				printf("Closing sockets\n");
				close(tuner->devhandles[i]);
			}
			tuner->devhandles[i] = -1;
		}
//		printf("[ATSC] Stopping & Flushing tuner: %s\n", tuner->name);
	}
	return ret;
}


uint8_t atsc_destroy(TUNER_STRUCT * tuner)
{
	TUNER_STRUCT * del = NULL;
	printf("[ATSC] Exiting, cleaning up..\n");

/*
	while(tuner)
	{
		printf("1\n");
		tuner = tuner->next;
		device_tuner_destroy(tuner);
		printf("2\n");
		del = tuner;
		printf("3\n");
		tuner = tuner->next;
//		printf("4\n");
		if (del)
		{
//			mpegts_io_close(del->mpegts_io, 1);
			//free(del);
		}
	}
	printf(".");
*/
	device_destroy(tuner->parent);
	printf(".\n");
	return 0;
}

uint8_t atsc_read_data(TUNER_STRUCT * tuner)
{
	uint8_t ret = 1;
	if (tuner && tuner->read_data_ptr && tuner->extra_data[0])
	{
//		int err = 0;
		size_t bytes_read = 0, offset = 0;
		size_t read_sz = tuner->read_size;

		ret = 0;

		if (!tuner->devhandles[0])
		{
			printf("ATNOOOOOOOOOOOOOOO\n");
		}

//		printf("HI1, sock: %d, sz: %" PRId64"\n", tuner->devhandle, read_sz);

		do
		{
			if (offset == 0)
			{
				uint32_t count = 0;
//				bytes_read = get_bytes_from_socket(tuner->devhandles[0], tuner->read_data_ptr, 1, 4000, &err);
				bytes_read = get_bytes_from_file(tuner->devhandles[0], tuner->read_data_ptr, 1);
				if ((int64_t)bytes_read <= -1)
				{
					printf("[ATSC] 1atsc_read_data, get_bytes err: %s (%d) (%" PRId64")\n",  strerror(errno), errno, (int64_t)bytes_read);
					return 0;
				}

				if (!(bytes_read == 1 && tuner->read_data_ptr[0] == TS_SYNC_BYTE))
				{
					DEVICE_STRUCT *device = tuner->parent;
//					TUNER_ATSC_STRUCT *atsc_device = device->parent;
//					win_screen_printw(atsc_device->screen, "Need sync..\n");
					utils_log_print(device->log, "Need sync.. %" PRId64" -- 0x%02x\n", bytes_read, tuner->read_data_ptr[0] );
					usleep(1000*500);
					count++;
					if (count < 5)
						continue;
					else
						return 1;
				}
			}
			else
			{
//				bytes_read = get_bytes_from_socket(tuner->devhandles[0], tuner->read_data_ptr + offset, read_sz, 2, 0, tuner->read_block_time);
				bytes_read = get_bytes_from_file(tuner->devhandles[0], tuner->read_data_ptr + offset, read_sz);
			}
//			bytes_read = get_bytes_from_file(tuner->devhandles[0], tuner->read_data_ptr + offset, read_sz);

//			printf("[%s %d] R: %" PRId64"\n", tuner->name, tuner->id,bytes_read);
			if ((int64_t)bytes_read <= -1)
			{
//				printf("[ATSC] atsc_read_data, get_bytes err: %s (%d) (%" PRId64")\n",  strerror(errno), errno, (int64_t)bytes_read);
				ret = 1;
				break;
			}
			else if (bytes_read == 0)
			{
				usleep(tuner->read_thread_sleep_time);
			}

			read_sz -= bytes_read;
			offset += bytes_read;
		}
		while (offset < tuner->read_size);
	}
	else
	{
//		printf("[ATSC] ceton_read_data error, something null\n");
	}
	return ret;
}


uint8_t atsc_update_stats(TUNER_STRUCT *tuner)
{
	if (tuner)
	{
		ioctl(tuner->devhandle, FE_READ_SIGNAL_STRENGTH, &tuner->signal_strength);
		ioctl(tuner->devhandle, FE_READ_SNR, &tuner->signal_noise_ratio);
/*
		uint16_t tmp;
		ioctl(tuner->devhandle, FE_READ_SIGNAL_STRENGTH, &tmp);
		tuner->signal_strength = ((tmp * 100) / 0xffff);
		ioctl(tuner->devhandle, FE_READ_SNR, &tmp);
		tuner->signal_noise_ratio = ((tmp * 100) / 0xffff);
*/
		return 1;
	}
	return 0;
}
/*
int check_frontend (int fe_fd)
{
	fe_status_t status;
	uint16_t snr, signal;
	uint32_t ber, uncorrected_blocks;
	do {
		ioctl(fe_fd, FE_READ_STATUS, &status);
		ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal);
		ioctl(fe_fd, FE_READ_SNR, &snr);
		ioctl(fe_fd, FE_READ_BER, &ber);
		ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);

		printf ("status %02x | signal %04x | snr %04x | "
			"ber %08x | unc %08x | ",
			status, signal, snr, ber, uncorrected_blocks);

		if (status & FE_HAS_LOCK)
			printf("FE_HAS_LOCK");

		usleep(1000000);

		printf("\n");
	} while (1);
	return 0;
}
*/

TUNER_ATSC_STRUCT * tuner_atsc_init(DEVICE_INIT_ARGS_STRUCT *devopts)
{
	TUNER_ATSC_STRUCT * atscdev = NULL;

	if (devopts && devopts->device_name && devopts->channels_file && devopts->bind_ip && devopts->bind_port)
	{
		atscdev = calloc(1, sizeof(TUNER_ATSC_STRUCT));
		if (atscdev)
		{
			char *tmp_adapter = NULL;
			int8_t tmp_num = -1;
//			printf("[ATSC] DVB ATSC Device init, using adapters: ");

			tmp_adapter = strtok(devopts->device_name, ",");
			while(tmp_adapter)
			{
				tmp_num = atoi(tmp_adapter);
//				printf("%d", tmp_num);

				atscdev->device_num[atscdev->device_count++] = tmp_num;

				tmp_adapter = strtok(NULL, ",");
//				if (tmp_adapter)
//					printf(", ");
			}
//			printf("\n");
			atscdev->channels_file = strdup(devopts->channels_file);
			atscdev->device = device_init(devopts->bind_ip, devopts->bind_port);

			if (atscdev->device)
			{
				TUNER_STRUCT *tmptuner = NULL;
//				char tmpdev1[MAX_DEVNAME_SIZE] = {0};
//				char tmpdev2[MAX_DEVNAME_SIZE] = {0};
				int i, tmp = atscdev->device_count;



				atscdev->device->stream_only = 1;
				_atsc_get_channel_lineup(atscdev);

				pthread_mutex_lock(&atscdev->device->tunerlock);
				atscdev->device->parent = (void *) atscdev;


				atscdev->device->cb_dev_printf = generic_vprintw;
				atscdev->device->cb_gui_incoming_parse = _gui_incoming_parse;

				if (!devopts->dvb_default_path)
					devopts->dvb_default_path = ATSC_DVB_DEFAULT_PATH;

				for (i=0; i < tmp; i++)
				{
					tmptuner = device_tuner_init(TUNE_TYPE_DVB_ATSC);

					if (tmptuner)
					{
						struct dvb_frontend_parameters *frontend_param = calloc(1, sizeof(struct dvb_frontend_parameters));
						snprintf(tmptuner->frontend, MAX_DEVNAME_SIZE, "%s%i/frontend0", devopts->dvb_default_path, atscdev->device_num[i]);
						snprintf(tmptuner->demux, MAX_DEVNAME_SIZE, "%s%i/demux0", devopts->dvb_default_path, atscdev->device_num[i]);
						snprintf(tmptuner->dvr, MAX_DEVNAME_SIZE, "%s%i/dvr0", devopts->dvb_default_path, atscdev->device_num[i]);

						tmptuner->devhandle = open(tmptuner->frontend, O_RDWR);

						if (tmptuner->devhandle > 2)
						{
							struct dvb_frontend_info fe_info;
							if (ioctl(tmptuner->devhandle, FE_GET_INFO, &fe_info) < 0 || fe_info.type != FE_ATSC)
							{
								close(tmptuner->devhandle);
								tmptuner->devhandle = 0;
							}
							else
							{
//								printf("[ATSC] Initialized: %s on adapter: %d\n", fe_info.name, i);
//								printf("\t%s\n", tmptuner->frontend);
//								printf("\t%s\n", tmptuner->demux);
								strncpy(tmptuner->name, fe_info.name, sizeof(tmptuner->name)-1);
							}
						}

						if (tmptuner->devhandle > 2)
						{
							int q;
							for (q=0; q < TUNER_MAX_DVB_HANDLES; q++)
								tmptuner->devhandles[q] = -1;

							tmptuner->segment_dir = devopts->segment_dir;
							tmptuner->base_filename = devopts->base_filename;

							tmptuner->mpegts_fileunit_maxsize = devopts->max_segment_size;
							tmptuner->mpegts_fileunit_maxlife = devopts->max_segment_life;

							tmptuner->extra_data[0] = (void *) frontend_param;
//							printf("[ATSC] File Segment Size: %d, Life (s): %d\n", tmptuner->mpegts_fileunit_maxsize, tmptuner->mpegts_fileunit_maxlife);
							tmptuner->read_thread_sleep_time = 64*1000;

							tmptuner->cb_read_data = atsc_read_data;
							tmptuner->cb_close_data = atsc_close_data;
							tmptuner->cb_tune_channel = atsc_tune_channel;
							tmptuner->cb_update_tuner_stats = atsc_update_stats;

//							tmptuner->packets_to_buffer = ATSC_DEFAULT_READ_SZ/188;
							tmptuner->packets_to_buffer = 10;
							tmptuner->read_size = ATSC_DEFAULT_READ_SZ;
							tmptuner->parent = (void*) atscdev->device;

							tmptuner->cb_gui_tuner_read_status  = win_tuner_read_status;
							tmptuner->cb_gui_tuner_write_status  = win_tuner_write_status;
							tmptuner->id_offset = 1;
							tmptuner->id = i+1;

							device_tuner_add(atscdev->device, tmptuner);
						}
						else
						{
							atscdev->device_num[i] = -1;
//							atscdev->device_count--;
							free(tmptuner);
						}

// Fix the Array here
					}
				}
				pthread_mutex_unlock(&atscdev->device->tunerlock);
			}
			else
			{
//				printf("I iz sad\n");
				pthread_mutex_unlock(&atscdev->init_mutex);
			}
		}
	}
	return atscdev;

}


#ifdef _MAIN_

#define MAIN_WIN_TITLE "[Main Output -- Ver 1] "


uint8_t sigint_h = 0;
uint8_t use_curses = 1;

TUNER_ATSC_STRUCT * atsc_device = NULL;
DEVICE_INIT_ARGS_STRUCT _opts = {	.bind_ip = ATSC_DEFAULT_BINDIP,
									.bind_port = ATSC_DEFAULT_BINDPORT,
									.max_segment_size = MPEGTS_IO_MAX_SIZE_DEFAULT,
									.channels_file = ATSC_DEFAULT_CHANNELS_CONF,
									.device_name = NULL,
									.atsc_id = CHANNELS_CONF_ID_ATSC
								};

void display_usage(char *exe)
{
}


static const char *optString = "1:2:s:f:l:p:c:a:n?h";

static const struct option longOpts[] =
{
	{ "help", no_argument, NULL, 'h' },
	{ NULL, no_argument, NULL, 0 }
};

uint8_t get_opts(int argc, char *const argv[], DEVICE_INIT_ARGS_STRUCT *devopts)
{
	int index = 0;
	int opt = getopt_long( argc, argv, optString, longOpts, &index );

	if (opt == -1 )
	{
		display_usage(argv[0]);
		return 1;
	}


	while ( opt != -1 )
	{
		switch ( opt )
		{
			case '1':
				devopts->max_segment_size = atoi(optarg);
				break;

			case '2':
				devopts->max_segment_life = atoi(optarg);
				break;

			case 'l':
				devopts->bind_ip = optarg;
				break;

			case 'p':
				devopts->bind_port = atoi(optarg);
				break;

			case 'c':
				devopts->channels_file = optarg;
				break;

			case 'a':
				devopts->device_name = optarg;
				break;

			case 's':
				devopts->segment_dir = optarg;
				break;

			case 'f':
				devopts->base_filename = optarg;
				break;

			case 'n':
				use_curses = !use_curses;
				break;

			case 'h':
			case '?':
				display_usage(argv[0]);
				break;

			default:
				break;
		}
		opt = getopt_long( argc, argv, optString, longOpts, &index );
	}
	return 0;
}

void sigint_handler()
{
//   printf("SIGINT caught\n");
//	sigint_h = 1;
	if (!sigint_h)
	{
		if (!use_curses)
		{
			pthread_mutex_unlock(&atsc_device->init_mutex);
		}
		sigint_h = 1;
	}
}

void sigpipe_handler()
{
//   printf("SIGPIPE caught\n");
}

int main(int argc, char *argv[])
{
	signal(SIGPIPE,sigpipe_handler);
	signal(SIGINT,sigint_handler);

	get_opts(argc, argv, &_opts);
	_opts.max_segment_size = get_nearest_page_size(_opts.max_segment_size, TS_PACKET_SIZE);
	if (!_opts.device_name)
	{
//		printf("[ATSC] No ATSC device name specified, exiting\n");
		return 1;
	}

	atsc_device = tuner_atsc_init(&_opts);

	if (atsc_device && atsc_device->device)
	{
		if (use_curses)
		{
			int ch, loop = 1;
			atsc_device->screen = edpvr_win_init(atsc_device->device);

			while (loop && !sigint_h)
			{
//				ch = wgetch(atsc_device->screen->main_window->handle);
				ch = getch();
				switch (ch)
				{
					case 'q' :
					case 'Q' :
						loop = 0;
					break;

					case ERR:
					{
						char *msg = NULL;
						do
						{
							msg = utils_log_getmsg(atsc_device->device->log);
							if (msg)
							{
								win_screen_printw(atsc_device->screen, msg);
//								wprintw(atsc_device->screen->main_window->handle, "%s", msg);
//								wrefresh(atsc_device->screen->main_window->handle);
								free(msg);
							}
						} while (msg);
						usleep(1000 * 250);
//						refresh();
						win_screen_update_all(atsc_device->screen);
					}
					break;

					default:
					break;
				}
			}
		}
		else
		{
			char *msg = NULL;
			while(!sigint_h)
			{
				do
				{
					msg = utils_log_getmsg(atsc_device->device->log);
					if (msg)
					{
//						win_screen_printw(restream_device->screen, msg);
						printf("%s", msg);
						free(msg);
					}
				} while (msg);
				usleep(1000);
			}
		}

		if (atsc_device && atsc_device->device && atsc_device->device->first_tuner)
			atsc_destroy(atsc_device->device->first_tuner);

		if (use_curses)
		{
			win_destroy_screen(atsc_device->screen);
		}
	}
	printf("[ATSC] App exiting, you may need to CTRL-C to break out\n");
	usleep(1000*1000);
	return 0;
}
#endif
